#include "GlobalOrderLoader.h"

GlobalOrderLoader::GlobalOrderLoader(const QString &user, const QString &passwd, uint bufferCapacity)
    : BaseLoader(user, passwd, bufferCapacity)
{
    if (!_sqlQuery.exec("use dbglobalorder;") || !_sqlQuery.exec("CALL cleanDatabase;")) {
        cout << "Nao foi possivel limpar o conteudo do banco de dados" << endl;
        cout << _sqlQuery.lastError().text().toStdString() << endl;
        throw -1;
    }
}

EdgeElement* GlobalOrderLoader::newElement(EdgeElement* parent, uint id, const QString& value, uint path_id, bool attribute) const
{
    EdgeElement * element = new EdgeElement();
    // incrementa antes de adicionar, pois a raiz deve ter código 1
    // código 0 fica como "pai da raiz"
    element->id = id;
    element->order = id;
    element->path_id = path_id;
    element->end_desc_id = element->id;
    if (parent) {
        element->parent_id = parent->id;
//        parent->end_desc_id = element->id;
    } else {
        element->parent_id = 0;
    }
    element->num_children = 0;
    element->value = value;
    element->attribute = attribute;

    return element;
}

void GlobalOrderLoader::duplicateLastAct()
{
    struct timespec _startTime,
        _endTime;

//    _sqlQuery.exec("use dbglobalorder;");
    clock_gettime(CLOCK_MONOTONIC, &_startTime);
    if (!_sqlQuery.exec("CALL copyLastAct();"))
        cout << "Falha ao executar o procedimento copyLastAct" << endl;
    clock_gettime(CLOCK_MONOTONIC, &_endTime);

    cout << "duplicate-last-act-ms " << (uint) timespecToMilisecond(_endTime) - timespecToMilisecond(_startTime) << " "; // tempo de processamento em ms
}

void GlobalOrderLoader::deleteFirstAct()
{
    struct timespec _startTime,
        _endTime;

//    _sqlQuery.exec("use dbglobalorder;");
    clock_gettime(CLOCK_MONOTONIC, &_startTime);
    if (!_sqlQuery.exec("CALL deleteFirstAct();"))
        cout << "Falha ao executar o procedimento deleteFirstAct" << endl;
    clock_gettime(CLOCK_MONOTONIC, &_endTime);

    cout << "delete-first-act-ms " << (uint) timespecToMilisecond(_endTime) - timespecToMilisecond(_startTime) << " "; // tempo de processamento em ms
}

void GlobalOrderLoader::dumpDatabase(QString filename)
{
    QFile file(filename);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        cout << "Nao foi possivel abrir o arquivo de destino do xml" << endl;
        throw -1;
    }

    file.write("<?xml version='1.0' encoding='UTF-8'?>");

    QSqlQueryModel model;

    _sqlQuery.exec("use dbglobalorder;");
    QString query("SELECT e.*, p.value AS label FROM edge e JOIN path p ON e.path_id = p.id ORDER BY e._order;");
    model.setQuery(query, QSqlDatabase::database());

    vector<EdgeElement*> ancestor;
    QString buffertofile;

    for (int i = 0; i < model.rowCount(); ++i) {
        EdgeElement* element = new EdgeElement();
        loadEdgeElement(model.record(i), element);
        element->label = getLastLabel(element->label);

        if (element->attribute) {
            buffertofile += " " + element->label + "=" + element->value;
            delete element;
        } else {
            if (!ancestor.empty()) {
                EdgeElement* father = ancestor.back();

                // fecha a tag anterior e escreve o texto
                buffertofile += ">";
                if (!father->value.isEmpty()) {
                    buffertofile += father->value;
                }

                // o father na verdade é um irmão, fecha a tag dele e retira da lista
                while (father->id != element->parent_id) {
//                    buffertofile += QString("    ").repeated(ancestor.size()-1);
                    buffertofile += "</" + father->label + ">";
                    ancestor.pop_back();
                    delete father;
                    father = ancestor.back();
                }
            }
            buffertofile += QString("    ").repeated(ancestor.size());
            buffertofile += "\n<" + element->label;
            ancestor.push_back(element);
        }
    }

    // fecha a tag anterior e escreve o texto
    buffertofile += ">";
    if (!ancestor.back()->value.isEmpty()) {
        buffertofile += ancestor.back()->value;
    }

    while (!ancestor.empty()) {
        EdgeElement* father = ancestor.back();
//        buffertofile += QString("    ").repeated(ancestor.size()-1);
        buffertofile += "</" + father->label + ">\n";
        ancestor.pop_back();
        delete father;
    }

    file.write(buffertofile.toUtf8());

    file.close();
}
